package com.zmn.oms.dubbo.impl.zmn.normal.part;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.zmn.base.oms.common.model.es.orderpart.EsOrderPart;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.oms.business.interfaces.es.OrderPartEsBService;
import com.zmn.oms.common.constant.OrderConsts;
import com.zmn.oms.common.dro.part.OrderAggrPartDRO;
import com.zmn.oms.common.dro.part.OrderPartDetailDRO;
import com.zmn.oms.dubbo.dto.common.work.OrderPartDRO;
import com.zmn.oms.dubbo.interfaces.zmn.normal.part.ZsNormalOrderPartRemoteService;
import com.zmn.oms.dubbo.utils.DubboConsts;
import com.zmn.oms.manager.utils.ElasticConsts;
import com.zmn.oms.model.entity.part.OrderPart;
import com.zmn.oms.services.interfaces.part.OrderPartService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Service;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;

import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 类描述：工单配件
 *
 * @author heciqi
 * @date 2018/11/28 20:19
 */
@Slf4j
@Service(loadbalance = "roundrobin", timeout = 5000, retries = 2, version = DubboConsts.INTERFACE_VERSION, validation = "true")
public class ZsNormalOrderPartRemoteServiceImpl implements ZsNormalOrderPartRemoteService {
    private static final String TAG = "啄木鸟-普通工单-工单配件dubbo接口";
    @Autowired
    private OrderPartService orderPartService;
    @Autowired
    OrderPartEsBService orderPartEsBService;
    /**
     * 获取配件
     * @param workIds
     * @return
     */
    public ResponseDTO<OrderAggrPartDRO> listAggrPartByWorkIds(List<Long> workIds, Integer masterId) {

        log.info("ZsNormalOrderPartRemoteService#listAggrPartByWorkIds 入参{},{masterId}", workIds);
        // 查询配件
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                .filter(QueryBuilders.termsQuery("orderId", workIds));
        if (Objects.nonNull(masterId)) {
            queryBuilder.filter(QueryBuilders.termQuery("masterId", masterId));
        }

        NativeSearchQuery searchQuery = new NativeSearchQuery(queryBuilder);
        searchQuery.setPageable(PageRequest.of(0, 1000));
        List<EsOrderPart> esOrderParts = orderPartEsBService.listPageByQuery(searchQuery);
        if (CollectionUtil.isNullOrEmpty(esOrderParts)) {
            OrderAggrPartDRO build = OrderAggrPartDRO.builder()
                    .deliverList(Collections.emptyList())
                    .inSourcingPartList(Collections.emptyList())
                    .outSourcingPartList(Collections.emptyList())
                    .build();
            return ResponseDTO.success(build);
        }

        // 聚合处理
        Map<String, List<EsOrderPart>> inParts = esOrderParts.stream()
                .filter(e -> Objects.equals(OrderConsts.PART_TYPE_SOURCING_IN, e.getPartType()))
                .collect(Collectors.groupingBy(EsOrderPart::getPartFullName));
        Map<String, List<EsOrderPart>> outParts = esOrderParts.stream()
                .filter(e -> Objects.equals(OrderConsts.PART_TYPE_SOURCING_OUT, e.getPartType()))
                .collect(Collectors.groupingBy(EsOrderPart::getPartFullName));
        Map<String, List<EsOrderPart>> delivers = esOrderParts.stream()
                .filter(e -> Objects.equals(OrderConsts.PART_TYPE_DELIVER, e.getPartType()))
                .collect(Collectors.groupingBy(EsOrderPart::getPartFullName));

        OrderAggrPartDRO orderAggrPartDRO = new OrderAggrPartDRO();
        orderAggrPartDRO.setInSourcingPartList(this.listAggrPart(inParts));
        orderAggrPartDRO.setOutSourcingPartList(this.listAggrPart(outParts));
        orderAggrPartDRO.setDeliverList(this.listAggrPart(delivers));
        log.info("ZsNormalOrderPartRemoteService#listAggrPartByWorkIds 出参{}", orderAggrPartDRO);
        return ResponseDTO.success(orderAggrPartDRO);
    }

    @Override
    public ResponseDTO<List<OrderPartDRO>> listOrderPartByOrderId(@NotNull(message = "订单号不能为空") Long orderId) {
        try {
            log.info("ZsNormalOrderPartRemoteServiceImpl#listOrderPartByOrderId 入参 orderId：{}", orderId);
            List<OrderPart> orderParts = orderPartService.listOrderPartByOrderId(orderId);
            log.info("ZsNormalOrderPartRemoteServiceImpl#listOrderPartByOrderId 出参 orderId：{}", JSON.toJSONString(orderParts));
            List<OrderPartDRO> orderPartDROList = BeanMapper.mapList(orderParts, OrderPartDRO.class);
            return ResponseDTO.success(orderPartDROList);
        } catch (Exception e) {
            log.error("ZsNormalOrderPartRemoteServiceImpl#listOrderPartByOrderId 失败 异常：{}", e);
            return ResponseDTO.fail(e.getMessage());
        }
    }

    /**
     * 计算配件数和配件金额
     * @param parts
     * @return
     */
    private List<OrderPartDetailDRO> listAggrPart(Map<String, List<EsOrderPart>> parts) {
        List<OrderPartDetailDRO> partDetailDROS = Lists.newArrayList();
        parts.forEach((partFullName, list) -> {
            if (CollectionUtil.isNullOrEmpty(list)) {
                return;
            }
            OrderPartDetailDRO obj = new OrderPartDetailDRO();
            obj.setPartFullName(partFullName);
            obj.setUnit(list.get(0).getUnit());
            obj.setNumber(list.stream()
                    .filter(e->Objects.nonNull(e.getNumber()))
                    .map(EsOrderPart::getNumber)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            obj.setAmount(list.stream()
                    .filter(e->Objects.nonNull(e.getAmount()))
                    .mapToLong(e->e.getAmount())
                    .sum());
            partDetailDROS.add(obj);
        });
        return partDetailDROS;
    }
}
